package com.thwj.project.app.service;

import cn.hutool.core.util.PhoneUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.thwj.common.exception.ServiceException;
import com.thwj.common.utils.DistanceUtil;
import com.thwj.common.utils.IDUtils;
import com.thwj.common.utils.StringUtils;
import com.thwj.common.utils.WzDateUtil;
import com.thwj.framework.mybatis_plus.GeoUtil;
import com.thwj.framework.security.LoginUser;
import com.thwj.framework.web.service.TokenService;
import com.thwj.project.amap.AMapService;
import com.thwj.project.amap.dto.AppLocationDTO;
import com.thwj.project.app.api.param.ActivityCancelParam;
import com.thwj.project.app.api.param.ActivityHomeParam;
import com.thwj.project.app.api.param.ActivityParam;
import com.thwj.project.app.api.param.ActivitySignUpParam;
import com.thwj.project.app.api.vo.*;
import com.thwj.project.app.event.ActivityCreateSuccessEvent;
import com.thwj.project.app.event.ActivitySignUpSuccessEvent;
import com.thwj.project.app.event.CancelActivitySignUpSuccessEvent;
import com.thwj.project.app.event.UserMessageEvent;
import com.thwj.project.biz.domain.*;
import com.thwj.project.biz.enums.*;
import com.thwj.project.biz.service.*;
import com.thwj.project.pay.OrderNumberUtil;
import com.thwj.project.pay.WxPayManger;
import com.thwj.project.pay.domain.WxPay;
import com.thwj.project.pay.dto.PayResultDTO;
import com.thwj.project.pay.dto.WxPayJSAPIDto;
import com.thwj.project.pay.enums.OrderSourceTypeEnum;
import com.thwj.project.pay.enums.PayStatusEnum;
import com.thwj.project.pay.service.IWxPayService;
import com.thwj.project.push.enums.PushTemplateEnumNew;
import com.thwj.project.push.event.WxMpMessageEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Transactional
@Service
public class AppActivityService {

    @Autowired
    IActivityService activityService;
    @Autowired
    AppUserService appUserService;
    @Autowired
    IUserService userService;
    @Autowired
    AMapService aMapService;
    @Autowired
    IActivitySignupService activitySignupService;
    @Autowired
    UserInfoResolver userInfoResolver;
    @Autowired
    WxPayManger wxPayManger;
    @Autowired
    IWxPayService wxPayService;
    @Autowired
    TokenService tokenService;
    @Autowired
    IActivityCategoryService activityCategoryService;
    @Autowired
    ApplicationEventPublisher applicationEventPublisher;
    @Autowired
    IUserAccountInoutService userAccountInoutService;
    @Autowired
    IUserAccountService userAccountService;
    @Autowired
    AppMerchantService appMerchantService;
    @Autowired
    UserVipResolver userVipResolver;
    @Autowired
    AppProductService appProductService;

    public Activity createUpdateActivity(ActivityParam activityParam, LoginUser loginUser) {
        // 检查用户是否 信息完整
        User user =  appUserService.userNeedInfoComplete(loginUser);
        // 参数相关数据合法性判断
        paramValidCheck(activityParam,user);
        // 检查用户信息是否完整
        appUserService.userNeedInfoComplete(loginUser);
        Activity activity = null;
        // 创建活动
        if (activityParam.getId() != null) {
            activity = activityService.getById(activityParam.getId());
        }else {
            activity = new Activity();
            activity.setStatus(ActivityStatusEnum.signUpIng.getValue());
            activity.setCreateDate(new Date());
            activity.setUserId(loginUser.getUserId());
            activity.setAuthenticationType(user.getAuthenticationType());
            activity.setOfficeUser(user.getOfficeUser());
            activity.setType(activityParam.getType());
            // 默认为每个人最多挂人1个
            activity.setTogetherMaxCount(1);
        }
        // 赋值
        activity.setCategoryId(activityParam.getCategoryId());
        // 根据经纬度获取行政区域
        AppLocationDTO appLocationDTO = aMapService.getAppLocationDTO(activityParam.getLongitude() + "," +activityParam.getLatitude());
        if (appLocationDTO != null) {
            activity.setCodeProv(appLocationDTO.getCodeProv());
            activity.setNameProv(appLocationDTO.getNameProv());
            activity.setCodeCity(appLocationDTO.getCodeCity());
            activity.setNameCity(appLocationDTO.getNameCity());
            activity.setCodeDistrict(appLocationDTO.getCodeDistrict());
            activity.setNameDistrict(appLocationDTO.getNameDistrict());
        }
        activity.setMerchantId(activityParam.getMerchantId());
        activity.setProductId(activityParam.getProductId());
        activity.setShowPublic(activityParam.getShowPublic());
        activity.setAddress(activityParam.getAddress());
        activity.setLocationName(activityParam.getName());
        activity.setLatitude(activityParam.getLatitude());
        activity.setLongitude(activityParam.getLongitude());
        // mysql gem
        activity.setLocation(GeoUtil.getWgs84Point(activityParam.getLatitude(),activityParam.getLongitude()));
        activity.setTitle(activityParam.getTitle());
        activity.setDescribePic(activityParam.getDescribePic());
        activity.setPicList(activityParam.getPicList());
        activity.setFormType(activityParam.getFormType());
        activity.setMaxSignUpCount(activityParam.getMaxSignUpCount());
        activity.setMaxManCount(activityParam.getMaxManCount());
        activity.setMaxWomanCount(activityParam.getMaxWomanCount());
//        activity.setStartDate(WzDateUtil.string2Date(activityParam.getStartDate(),WzDateUtil.TIME_FORMAT_A));
        activity.setStartDate(activityParam.getStartDate());
        activity.setEndDate(activityParam.getEndDate());
        activity.setCancelFreeType(activityParam.getCancelFreeType());
        // 获取无责失效
        ActivityCancelBeforeTypeEnum cancelBeforeTypeEnum = ActivityCancelBeforeTypeEnum.getEnumByValue(activityParam.getCancelFreeType());
        if(!ActivityCancelBeforeTypeEnum.cannot.equals(cancelBeforeTypeEnum)) {
            activity.setCancelFreeDate(WzDateUtil.setSecond(activity.getStartDate(), - cancelBeforeTypeEnum.getSecondBefore()));
        }
        activity.setDescribeContent(activityParam.getDescribeContent());
        activity.setDescribePic(activityParam.getDescribePic());
        activity.setChargeType(activityParam.getChargeType());
        activity.setPayWay(activityParam.getPayWay());
        activity.setPrice(activityParam.getPrice());
        activity.setDiscountType(activityParam.getDiscountType());
        activity.setDiscountedPrice(activityParam.getDiscountedPrice());

        // 如果前端没有穿就 默认使用创建者的信息
        if(StringUtils.isEmpty(activityParam.getContactName())) {
            activity.setContactName(user.getUserNickName());
        } else {
            activity.setContactName(activityParam.getContactName());
        }
        if(StringUtils.isEmpty(activityParam.getContactWechat())) {
            activity.setContactWechat(user.getWechat());
        } else {
            activity.setContactWechat(activityParam.getContactWechat());
        }
        if(StringUtils.isEmpty(activityParam.getContactPhone())) {
            activity.setContactPhone(user.getPhone());
        } else {
            activity.setContactPhone(activityParam.getContactPhone());
        }
        // 默认 开始时间截止报名
        activity.setSignUpEndDate(activity.getStartDate());
        // 乐观锁必须
        if(!activityService.saveOrUpdate(activity)){
            throw new ServiceException("数据已过期，请重新提交");
        }
        // 如果发现该互动时在指定商家下创建 提示商家
        applicationEventPublisher.publishEvent(
                ActivityCreateSuccessEvent.builder()
                        .activity(activity).build()
        );
        return activity;
    }


    // 参数相关数据合法性判断
    private void paramValidCheck(ActivityParam activityParam,User user) {
        if (activityParam.getType() == null) {
            throw new ServiceException("前端小哥活动类型是不是忘记传了");
        }
        if (activityParam.getCategoryId() == null) {
            throw new ServiceException("活动分类必填");
        }
        if (activityParam.getShowPublic() == null) {
            throw new ServiceException("请选择活动是否首页公开可见");
        }
        if (activityParam.getLatitude() == null || activityParam.getLongitude() == null || activityParam.getAddress() == null) {
            throw new ServiceException("活动地点必填");
        }
        if (StringUtils.isEmpty(activityParam.getTitle())) {
            throw new ServiceException("活动名称必填");
        }
        if (StringUtils.isEmpty(activityParam.getPicList())) {
            throw new ServiceException("活动图片必填");
        }
        if (activityParam.getFormType() == null) {
            throw new ServiceException("活动形式必填");
        }
        if (activityParam.getMaxSignUpCount() == null || activityParam.getMaxSignUpCount() < 1) {
            throw new ServiceException("报名人数必填");
        }
        if (activityParam.getStartDate() == null) {
            throw new ServiceException("活动时间必填");
        }
        if (activityParam.getStartDate().compareTo(new Date()) < 0) {
            throw new ServiceException("活动开始时间必须大于当前时间");
        }
        if (activityParam.getStartDate().compareTo(activityParam.getEndDate()) > 0) {
            throw new ServiceException("活动开始时间不能大于活动结束时间");
        }
        if (activityParam.getCancelFreeType() == null) {
            throw new ServiceException("无责取消时间必填");
        }
        if (activityParam.getChargeType() == null) {
            throw new ServiceException("收费类型必填");
        }
       /* if (StringUtils.isEmpty(activityParam.getContactPhone())) {
            throw new ServiceException("联系电话必填");
        }*/
        /*if (activityParam.getSignUpEndDate() == null) {
            throw new ServiceException("报名截止时间必填");
        }*/
        /*if (activityParam.getSignUpEndDate().compareTo(activityParam.getStartDate()) <= 0) {
            throw new ServiceException("报名截止时间不能晚于开始时间");
        }*/
        ActivityCancelBeforeTypeEnum cancelBeforeTypeEnum = ActivityCancelBeforeTypeEnum.getEnumByValue(activityParam.getCancelFreeType());
        if (cancelBeforeTypeEnum == null) {
            throw new ServiceException("无责取消时间必选");
        }

        ActivityFormTypeEnum formTypeEnum = ActivityFormTypeEnum.getEnumByValue(activityParam.getFormType());
        if(ActivityFormTypeEnum.diy.equals(formTypeEnum) && (activityParam.getMaxWomanCount() == null || activityParam.getMaxManCount() == null)) {
            throw new ServiceException("自定义活动形式需指定男女个数");
        }
        // 这里前段考虑 自定义男女个数时 总人数直接把两个相加 更新到前端页面的总人数 然后提交给我
        if(ActivityFormTypeEnum.diy.equals(formTypeEnum)) {
            if(activityParam.getMaxSignUpCount() != (activityParam.getMaxManCount() + activityParam.getMaxWomanCount()))
            throw new ServiceException("活动总人数必须等于自定义男女人数");
        }

        ActivityChargeTypeEnum chargeTypeEnum = ActivityChargeTypeEnum.getEnumByValue(activityParam.getChargeType());
        if(chargeTypeEnum == null) {
            throw new ServiceException("每人费用必填");
        }

        // 前端注意 只有AA制收费才有优惠类型的选择 （女生优惠）
        if (ActivityChargeTypeEnum.AA_before.equals(chargeTypeEnum)) {
            if(activityParam.getPrice() == null || activityParam.getPrice().compareTo(BigDecimal.ZERO) <= 0){
                throw new ServiceException("收费金额必须大于0");
            }
            ActivityDiscountTypeEnum discountTypeEnum = ActivityDiscountTypeEnum.getEnumByValue(activityParam.getDiscountType());
            if(discountTypeEnum != null && activityParam.getDiscountedPrice() == null) {
                throw new ServiceException("优惠价格必填");
            }
            if(discountTypeEnum != null && activityParam.getDiscountedPrice().compareTo(activityParam.getPrice()) > 0) {
                throw new ServiceException("优惠后的金额必须大于0");
            }
        }
        //
        if(user == null || UserStatusEnum.forbidden.getValue() == user.getStatus()) {
            throw new ServiceException("当前用户已被禁用，请联系客服处理");
        }
        // 俱乐部 权限 不能新增 可修改
        if (activityParam.getId() == null && user.getAuthenticationType() != null &&
                UserAuthenticationTypeEnum.club.getValue() != user.getAuthenticationType() &&
                activityParam.getType() == ActivityTypeEnum.party.getValue()) {
            throw new ServiceException("认证俱乐部成功后再发布该活动");
        }
    }

    /***
     * 读取活动详情信息
     * @param activityId
     * @return
     */
    public ActivityVo getActivityDetail(Long activityId, LoginUser loginUser) {
        //获取授权的经纬度
        Double lngLatArray[] = tokenService.getLngLatArray();
        // 查询数据
        Activity activity = activityService.getOne(
                new QueryWrapper<Activity>()
                        .eq("id",activityId)
                        .select(lngLatArray == null ? "*" :
                                String.format("*,ST_Distance_Sphere(ST_GeomFromText('POINT(%f %f)',4326), location) AS distance", lngLatArray[0], lngLatArray[1]))
        );
        if(activity == null) {
            throw new ServiceException("活动不存在");
        }
        // 更新状态
        updateActivityStatusAuto(activity);
        // 读取分类
        List<ActivityCategory> categoryList = activityCategoryService.list(null);
        // 构建返回数据
        ActivityVo activityVo = convertActivityVo(activity, categoryList);

        // 额外信息
        activityVo.setDescribeContent(activity.getDescribeContent());
        activityVo.setDescribePic(activity.getDescribePic());
        // 创建者的信息 这个要注意 在查看人没有报名 就不要暴露重要信息给前端
        User createUserDo = userService.getById(activity.getUserId());
        UserInfoVo createUser = new UserInfoVo();
        createUser.setUserId(createUserDo.getId());
        createUser.setNickname(createUserDo.getUserNickName());
        createUser.setHeadPic(createUserDo.getUserHeadPic() + "?x-oss-process=image/resize,h_100,m_lfit");
        createUser.setGender(createUserDo.getGender());
        createUser.setAuthenticationType(createUserDo.getAuthenticationType());
        createUser.setAuthenticationJobName(createUserDo.getAuthenticationJobName());
        createUser.setAuthenticationClubName(createUserDo.getAuthenticationClubName());
        activityVo.setCreateUser(createUser);
        if(activity.getMerchantId() != null) {
            // 商家信息
            MerchantVO merchantVO = appMerchantService.getMerchantDetail(activity.getMerchantId());
            activityVo.setMerchantVO(merchantVO);
        }
        if (activity.getProductId() != null) {
            MerchantProductVO merchantProductVO = appProductService.getProductById(activity.getProductId());
            activityVo.setMerchantProductVO(merchantProductVO);
        }

        // 如果当前登录了用户则更新用户相关数据
        if (loginUser != null) {
            ActivitySignup activitySignup = activitySignupService.getOne(
                    new QueryWrapper<ActivitySignup>().eq("activity_id",activityId)
                            .eq("user_id",loginUser.getUserId()).orderByDesc("create_date"), false
            );
            activityVo.setSignUpStatus(activitySignup == null ? ActivitySignUpStatusEnum.sign_up_wait_pay.getValue():activitySignup.getStatus());
            // 只有当用户是报名状态 才有创建者信息
            if (activitySignup != null &&ActivitySignUpStatusEnum.sign_up_ed.getValue() == activitySignup.getStatus()) {
                createUser.setPhone(createUserDo.getContactPhone());
                createUser.setWechat(createUser.getPhone());
            }
            User currentUser = userService.getById(loginUser.getUserId());

            if (ActivityChargeTypeEnum.AA_before.getValue() == activity.getChargeType() &&
                    activity.getDiscountedPrice().compareTo(BigDecimal.ZERO) > 0 &&
                    UserGenderEnum.woman.getValue() == currentUser.getGender() &&
                    ActivityDiscountTypeEnum.woman_discount.getValue() == activity.getDiscountType()
            ) {
                activityVo.setPayPrice(activity.getPrice().subtract(activity.getDiscountedPrice()).setScale(2, RoundingMode.HALF_UP));
            }
            // 当前用户是否有优惠
            if (ActivityDiscountTypeEnum.woman_discount.getValue() == activity.getDiscountType() && currentUser.getGender() == UserGenderEnum.woman.getValue()) {
                // 用户优惠金额
                activityVo.setDiscountedPrice(activity.getDiscountedPrice());
            }else {
                activityVo.setDiscountedPrice(BigDecimal.ZERO);
            }
            // 如果是当前用户创建者
            if(loginUser.getUserId().compareTo(activity.getUserId()) == 0) {
                activityVo.setMyActivity(true);
            }
        }
        // 读取报名人信息
        List<ActivitySignup> signupList = activitySignupService.list(new QueryWrapper<ActivitySignup>()
                .eq("activity_id", activityId)
                .eq("status", ActivitySignUpStatusEnum.sign_up_ed.getValue())
                .orderByAsc("pay_date"));
        if (!CollectionUtils.isEmpty(signupList)) {
            List<ActivityUserSignUpVo> userSignUpVoList  = signupList.stream().map(item->{
                ActivityUserSignUpVo signUpVo = new ActivityUserSignUpVo();
                signUpVo.setUserId(item.getUserId());
                return signUpVo;
            }).collect(Collectors.toList());
            // 统一更新 读取最新数据
            userInfoResolver.resolve(userSignUpVoList,ActivityUserSignUpVo::getUserId,(ActivityUserSignUpVo obj, String nickName, String headPic, Integer gender,String signature,String phone,String wechat)->{
                obj.setNickname(nickName);
                obj.setHeadPic(headPic);
                obj.setGender(gender);
                obj.setSignature(signature);
                obj.setPhone(phone);
                obj.setWecaht(wechat);
            });
            userVipResolver.resolve(userSignUpVoList, ActivityUserSignUpVo::getUserId,((obj, vipOrNot)->{
                obj.setVipOrNot(vipOrNot);
            }));
            // 如果是创建者 当前用户id = 活动创建人id
            if (loginUser != null && activity.getUserId().compareTo(loginUser.getUserId()) == 0){
                activityVo.setMyActivity(true);
                // 统一更新 读取最新数据
                userInfoResolver.resolve(userSignUpVoList,ActivityUserSignUpVo::getUserId,(ActivityUserSignUpVo obj, String nickName, String headPic, Integer gender,String signature,String phone,String wechat)->{
                    obj.setNickname(nickName);
                    obj.setHeadPic(headPic);
                    obj.setGender(gender);
                    obj.setSignature(signature);
                    obj.setPhone(phone);
                    obj.setWecaht(wechat);
                });
            }else {
                // 统一更新 读取最新数据
                userInfoResolver.resolve(userSignUpVoList,ActivityUserSignUpVo::getUserId,(ActivityUserSignUpVo obj, String nickName, String headPic, Integer gender,String signature,String phone,String wechat)->{
                    obj.setNickname(nickName);
                    obj.setHeadPic(headPic);
                    obj.setGender(gender);
                    obj.setSignature(signature);
//            obj.setPhone(phone);
//            obj.setWecaht(wechat);
                });
            }

            activityVo.setUserSignUpVoList(userSignUpVoList);
            //这里需要计算男女剩余人数
            if(activity.getFormType() == ActivityFormTypeEnum.diy.getValue()) {
                Long manCount = signupList.stream().filter(item->UserGenderEnum.man.getValue() == item.getGender()).count();
                Long woManCount = signupList.stream().filter(item->UserGenderEnum.woman.getValue() == item.getGender()).count();
                activityVo.setLeaveManCount(activity.getMaxManCount() - manCount.intValue());
                activityVo.setLeaveWomanCount(activity.getMaxWomanCount() - woManCount.intValue());
            }


        }
        // 更新
        userInfoResolver.resolve(activityVo,ActivityVo::getUserId,(obj, nickname,headPic)->{
            obj.setUserName(nickname);
            obj.setUserHeadPic(headPic + "?x-oss-process=image/resize,h_100,m_lfit");
        });
        userVipResolver.resolve(activityVo, ActivityVo::getUserId,((obj, vipOrNot)->{
            obj.setVipOrNot(vipOrNot);
        }));

        return activityVo;
    }

    /***
     * 更新活动 新增一个事务 这个只要调用就保证提交 不会影响业务
     * @param activity
     * @return
     */
    @Transactional
    public void updateActivityStatusAuto(Activity activity) {
        // 如果活动状态为已取消 则不需要更新状态
        if (ActivityStatusEnum.cancel.getValue() == activity.getStatus() ||
                ActivityStatusEnum.end.getValue() == activity.getStatus()) {
            return;
        }
        ActivityStatusEnum currentStatusEnum = null;
        // 当前时间 > 报名截止时间
        if(System.currentTimeMillis() > activity.getSignUpEndDate().getTime()) {
            currentStatusEnum = ActivityStatusEnum.signUpCutOff;
        }
        // 当前时间 > 开始时间
        if(System.currentTimeMillis() > activity.getStartDate().getTime()) {
            currentStatusEnum = ActivityStatusEnum.inProgress;
        }
        // 当前时间 > 结束时间
        if(System.currentTimeMillis() > activity.getEndDate().getTime()) {
            currentStatusEnum = ActivityStatusEnum.end;
        }
        if(currentStatusEnum != null) {
            // 更新状态
            activity.setStatus(currentStatusEnum.getValue());
            activityService.update(
                    new UpdateWrapper<Activity>()
                            .set("status",currentStatusEnum.getValue())
                            .eq("id", activity.getId())
            );
        }

    }



    private ActivityVo convertActivityVo(Activity activity,List<ActivityCategory> categoryList) {
        ActivityVo activityVo = new ActivityVo();
        activityVo.setId(activity.getId());
        activityVo.setType(activity.getType());
        activityVo.setCategoryId(activity.getCategoryId());
        List<ActivityCategory> categoryListOne = categoryList.stream().filter(item->item.getId().equals(activity.getCategoryId())).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(categoryListOne)) {
            activityVo.setCategoryName(categoryListOne.get(0).getName());
            activityVo.setCategoryIcon(categoryListOne.get(0).getIconPic());
        }
        activityVo.setAuthenticationType(activity.getAuthenticationType());
        activityVo.setOfficeUser(activity.getOfficeUser());
        activityVo.setShowPublic(activity.getShowPublic());
        activityVo.setAddress(activity.getAddress());
        activityVo.setLocationName(activity.getLocationName());
        activityVo.setDistanceShow(DistanceUtil.getDistanceString(activity.getDistance()));
        activityVo.setLatitude(activity.getLatitude());
        activityVo.setLongitude(activity.getLongitude());
        activityVo.setTitle(activity.getTitle());
        activityVo.setCoverPic(activity.getCoverPic());
        if(StringUtils.isNotEmpty(activity.getPicList())) {
            String picList[] = activity.getPicList().split(",");
            activityVo.setPicFirst(picList[0] + "?x-oss-process=image/resize,h_500,m_lfit/format,png");
        }
        activityVo.setPicList(activity.getPicList());
        if (StringUtils.isNotEmpty(activity.getPicList())) {
            String picList[] = activity.getPicList().split(",");
            List<String> picConvertList = Arrays.stream(picList).map(item->{
                return item + "?x-oss-process=image/format,png";
            }).collect(Collectors.toList());
            activityVo.setPicListV2(StringUtils.join(picConvertList,"|"));
        }
        activityVo.setFormType(activity.getFormType());
        activityVo.setMaxSignUpCount(activity.getMaxSignUpCount());
        activityVo.setSignUpCount(activity.getSignUpCount());
        activityVo.setMaxManCount(activity.getMaxManCount());
        activityVo.setMaxWomanCount(activity.getMaxWomanCount());
        activityVo.setLeaveManCount(activity.getMaxManCount());
        activityVo.setLeaveWomanCount(activity.getMaxWomanCount());
        activityVo.setStartDate(WzDateUtil.date2String(activity.getStartDate(),WzDateUtil.TIME_FORMAT_A));
        String startDateStr = String.format(
                "%s-%s %s %s",
                WzDateUtil.date2String(activity.getStartDate(),WzDateUtil.TIME_FORMAT_L),
                WzDateUtil.date2String(activity.getEndDate(),WzDateUtil.TIME_FORMAT_L),
                WzDateUtil.getWeekOfDate(activity.getStartDate()),
                WzDateUtil.date2String(activity.getStartDate(),WzDateUtil.DATE_FORMAT_N)
                );
        activityVo.setDateShow(startDateStr);
        activityVo.setDateDayShow(WzDateUtil.date2String(activity.getStartDate(),WzDateUtil.DATE_FORMAT_D));

        activityVo.setStartDate(WzDateUtil.date2String(activity.getStartDate(),WzDateUtil.TIME_FORMAT_A));
        activityVo.setEndDate(WzDateUtil.date2String(activity.getEndDate(),WzDateUtil.TIME_FORMAT_A));

        activityVo.setCancelFreeType(activity.getCancelFreeType());
        if(activity.getCancelFreeDate() != null) {
            activityVo.setCancelFreeTypeDesc(WzDateUtil.date2String(activity.getCancelFreeDate(),WzDateUtil.TIME_FORMAT_A));
        }
//        activityVo.setDescribeContent(activity.getDescribeContent());
        activityVo.setChargeType(activity.getChargeType());
        activityVo.setPayWay(activity.getPayWay());
        activityVo.setPrice(activity.getPrice());
        activityVo.setDiscountedPriceOrigin(activity.getDiscountedPrice());

        if (ActivityChargeTypeEnum.AA_before.getValue() == activity.getChargeType()){
            activityVo.setPayPrice(activity.getPrice().setScale(2, RoundingMode.HALF_UP));
        }
        // 展示价格的样式
        // 如果是免费 直接显示免费字样
        if (ActivityChargeTypeEnum.free.getValue() == activity.getChargeType()) {
            activityVo.setPriceShow(ActivityChargeTypeEnum.free.getName());
        } else {
            activityVo.setPriceShow(activity.getPrice().setScale(1,RoundingMode.HALF_UP).toString());
        }

        activityVo.setDiscountType(activity.getDiscountType());
        activityVo.setDiscountedPrice(activity.getDiscountedPrice());
        activityVo.setContactName(activity.getContactName());
        activityVo.setContactPhone(activity.getContactPhone());
        activityVo.setContactWechat(activity.getContactWechat());
        activityVo.setStatus(activity.getStatus());
        activityVo.setUserId(activity.getUserId());
        activityVo.setErCodeUrl(activity.getErCodeUrl());
       /* // 构建创建这信息
        UserInfoVo createUser = new UserInfoVo();
        activityVo.setCreateUser(createUser);
        createUser.setUserId(activity.getUserId());
        userInfoResolver.resolve(createUser,UserInfoVo::getUserId,(UserInfoVo obj, String nickName, String headPic, Integer gender,Integer authenticationType)->{
            obj.setNickname(nickName);
            obj.setHeadPic(headPic);
            obj.setGender(gender);
            obj.setAuthenticationType(authenticationType);
        });*/
        return activityVo;
    }


    private ActivityVo convertActivityHomeVo(Activity activity, List<ActivityCategory> categoryList) {
        ActivityVo activityVo = new ActivityVo();
        activityVo.setId(activity.getId());
        activityVo.setType(activity.getType());
        activityVo.setCategoryId(activity.getCategoryId());
        List<ActivityCategory> categoryListOne = categoryList.stream().filter(item->item.getId().equals(activity.getCategoryId())).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(categoryListOne)) {
            activityVo.setCategoryName(categoryListOne.get(0).getName());
            activityVo.setCategoryIcon(categoryListOne.get(0).getIconPic());
        }
        activityVo.setAuthenticationType(activity.getAuthenticationType());
        activityVo.setOfficeUser(activity.getOfficeUser());
        activityVo.setShowPublic(activity.getShowPublic());
        activityVo.setAddress(activity.getAddress());
        activityVo.setLocationName(activity.getLocationName());
        activityVo.setDistanceShow(DistanceUtil.getDistanceString(activity.getDistance()));
        activityVo.setLatitude(activity.getLatitude());
        activityVo.setLongitude(activity.getLongitude());
        activityVo.setTitle(activity.getTitle());
        activityVo.setCoverPic(activity.getCoverPic());

        if(StringUtils.isNotEmpty(activity.getPicList())) {
            String picList[] = activity.getPicList().split(",");
            activityVo.setPicFirst(picList[0] + "?x-oss-process=image/resize,h_500,m_lfit/format,png");
        }
        if(activity.getCancelFreeDate() != null) {
            activityVo.setCancelFreeTypeDesc(WzDateUtil.date2String(activity.getCancelFreeDate(),WzDateUtil.TIME_FORMAT_A));
        }
        activityVo.setPicList(activity.getPicList());
        if (StringUtils.isNotEmpty(activity.getPicList())) {
            String picList[] = activity.getPicList().split(",");
            List<String> picConvertList = Arrays.stream(picList).map(item->{
                return item + "?x-oss-process=image/format,png";
            }).collect(Collectors.toList());
            activityVo.setPicListV2(StringUtils.join(picConvertList,"|"));
        }

        activityVo.setFormType(activity.getFormType());
        activityVo.setMaxSignUpCount(activity.getMaxSignUpCount());
        activityVo.setSignUpCount(activity.getSignUpCount());
        activityVo.setMaxManCount(activity.getMaxManCount());
        activityVo.setMaxWomanCount(activity.getMaxWomanCount());
        activityVo.setStartDate(WzDateUtil.date2String(activity.getStartDate(),WzDateUtil.TIME_FORMAT_A));
        String startDateStr = String.format(
                "%s-%s %s %s",
                WzDateUtil.date2String(activity.getStartDate(),WzDateUtil.TIME_FORMAT_L),
                WzDateUtil.date2String(activity.getEndDate(),WzDateUtil.TIME_FORMAT_L),
                WzDateUtil.getWeekOfDate(activity.getStartDate()),
                WzDateUtil.date2String(activity.getStartDate(),WzDateUtil.DATE_FORMAT_N)
        );
        activityVo.setDateDayShow(WzDateUtil.date2String(activity.getStartDate(),WzDateUtil.DATE_FORMAT_D));
        activityVo.setDateShow(startDateStr);
        activityVo.setStartDate(WzDateUtil.date2String(activity.getStartDate(),WzDateUtil.TIME_FORMAT_A));
        activityVo.setEndDate(WzDateUtil.date2String(activity.getEndDate(),WzDateUtil.TIME_FORMAT_A));

        activityVo.setCancelFreeType(activity.getCancelFreeType());
        // 内容的数据量太大 只有在详情的时候给
//        activityVo.setDescribeContent(activity.getDescribeContent());
        activityVo.setChargeType(activity.getChargeType());
        activityVo.setPayWay(activity.getPayWay());
        // 如果是免费 直接显示免费字样
      /*  if (ActivityChargeTypeEnum.free.getValue() == activity.getChargeType()) {
            activityVo.setPriceShow(ActivityChargeTypeEnum.free.getName());
        }*/
        // 如果是AA预付
        // 展示价格的样式
        // 如果是免费 直接显示免费字样
        if (ActivityChargeTypeEnum.free.getValue() == activity.getChargeType()) {
            activityVo.setPriceShow(ActivityChargeTypeEnum.free.getName());
        } else {
            activityVo.setPriceShow(activity.getPrice().setScale(1,RoundingMode.HALF_UP).toString());
        }
        activityVo.setDiscountType(activity.getDiscountType());
        activityVo.setDiscountedPrice(activity.getDiscountedPrice());

        activityVo.setStatus(activity.getStatus());
        activityVo.setUserId(activity.getUserId());
        return activityVo;
    }

    /***
     * 读取活动相关分页数据
     * @param page
     * @param activityHomeParam
     * @return
     */
    public Page<ActivityVo> getActivityPage(Page page, ActivityHomeParam activityHomeParam) {
        //获取授权的经纬度
        Double lngLatArray[] = tokenService.getLngLatArray();
        log.info("经纬度：{}",lngLatArray);
        // 官方发布的活动置顶 只会出现在第一页 & 智能排序 & 其他都没有限制 其实就是打开首屏 展示
        List<Activity> topActivityList = null;
        List<Long> topActivityIdList = null;
        if (page.getCurrent() == 1 && activityHomeParam.getSortType() == 1 &&
                activityHomeParam.getStartDate() == null && activityHomeParam.getEndDate() == null &&
                activityHomeParam.getActivityCategoryId() == null && StringUtils.isEmpty(activityHomeParam.getSearchKey())) {
            topActivityList = activityService.list(
                    new QueryWrapper<Activity>()
                            // 官方活动
                            .eq("office_user",true)
                            // 固有规则 已结束 已取消 不展示
                            .lt("status", ActivityStatusEnum.end.getValue())
                            // 固有规则 只读取用户公开的活动
                            .eq("show_public",true)
                            // 页面不同 限定不同类型 活动 / 派对
                            // 这里有个特殊逻辑 甲方要求当 普通活动的时候 特殊处理官方派对 也要在type 为1的时候 混合展示
                            .eq(activityHomeParam.getActivityType() != null &&
                                    ActivityTypeEnum.party.getValue() == activityHomeParam.getActivityType(), "type", activityHomeParam.getActivityType())
                            // 前端用户 限定城市
//                            .eq(activityHomeParam.getCityCode() != null, "code_city", activityHomeParam.getCityCode())
                            .select(lngLatArray == null? "*" :
                                    String.format("*,ST_Distance_Sphere(ST_GeomFromText('POINT(%f %f)',4326), location) AS distance", lngLatArray[0], lngLatArray[1]))
            );
            topActivityIdList = topActivityList.stream().map(Activity::getId).collect(Collectors.toList());
        }


        Wrapper<Activity> activityWrapper = new QueryWrapper<Activity>()
                .and(StringUtils.isNotEmpty(activityHomeParam.getSearchKey()),
                        w->w.like("title", activityHomeParam.getSearchKey())
                                .or().like("location_name",activityHomeParam.getSearchKey()))
                // 固有规则 已结束 已取消 不展示
                .lt("status", ActivityStatusEnum.end.getValue())
                // 固有规则 只读取用户公开的活动
                .eq("show_public",true)
                .notIn( !CollectionUtils.isEmpty(topActivityIdList),"id", topActivityIdList)
                // 页面不同 限定不同类型 活动 / 派对
                .eq(activityHomeParam.getActivityType() != null, "type", activityHomeParam.getActivityType())
                // 前端用户 限定时间
                .between(activityHomeParam.getStartDate() != null && activityHomeParam.getEndDate() != null,"start_date", WzDateUtil.timestamp2Date(activityHomeParam.getStartDate()), WzDateUtil.timestamp2Date(activityHomeParam.getEndDate()))
                // 前端用户 限定分类
                .eq(activityHomeParam.getActivityCategoryId() != null, "category_id", activityHomeParam.getActivityCategoryId())
                // 前端用户 限定城市
                .eq(activityHomeParam.getCityCode() != null, "code_city", activityHomeParam.getCityCode())
                .select(lngLatArray == null ? "*" :
                        String.format("*,ST_Distance_Sphere(ST_GeomFromText('POINT(%f %f)',4326), location) AS distance", lngLatArray[0], lngLatArray[1]))
//                .select("*,ST_Distance_Sphere(ST_GeomFromText('POINT(120.20204 30.186620)',4326), location) AS distance")
                // 排序 智能排序 1级排序优先报名中 2级距离升序 3级 价格升序 4级 创建时间降序
                .orderBy(activityHomeParam.getSortType() == 1, true, "status")
                .orderBy(activityHomeParam.getSortType() == 1 && lngLatArray != null, true, "distance")
                .orderBy(activityHomeParam.getSortType() == 1, true, "price")
                .orderBy(activityHomeParam.getSortType() == 1, false, "id")
                // 排序 距离排序
                .orderBy(activityHomeParam.getSortType() == 2 && lngLatArray != null, true, "distance")
                .orderBy(activityHomeParam.getSortType() == 2, true, "status")
                .orderBy(activityHomeParam.getSortType() == 2, false, "id")
                // 排序 价格
                .orderBy(activityHomeParam.getSortType() == 3, true, "price")
                .orderBy(activityHomeParam.getSortType() == 3, true, "status")
                .orderBy(activityHomeParam.getSortType() == 3, false, "id");

        Page<Activity> activityPage = activityService.page(page,activityWrapper);

        List<ActivityCategory> categoryList = activityCategoryService.list(null);

        // 加工返回前端VO
        List<ActivityVo> activityVoList = new ArrayList<>();
        // 首屏置顶优先
        if (!CollectionUtils.isEmpty(topActivityList)) {
            topActivityList.forEach(item->{
                activityVoList.add(convertActivityHomeVo(item,categoryList));
            });
        }
        // 分页数据
        activityPage.getRecords().forEach(item->{
            activityVoList.add(convertActivityHomeVo(item,categoryList));
        });
        // 综合活动id
        List<Long> activityIdList = activityVoList.stream().map(ActivityVo::getId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(activityIdList)) {
            return page;
        }
        // 综合读取报名信息
        List<ActivitySignup> activitySignupList = activitySignupService.list(
                new QueryWrapper<ActivitySignup>()
                        .in("activity_id",activityIdList)
                        .eq("status",ActivitySignUpStatusEnum.sign_up_ed.getValue())
        );
        convertActivitySignUpUserList(activityVoList,activitySignupList);
        // 更新
        userInfoResolver.resolve(activityVoList,ActivityVo::getUserId,(obj, nickname,headPic)->{
            obj.setUserName(nickname);
            obj.setUserHeadPic(headPic + "?x-oss-process=image/resize,h_100,m_lfit");
        });

        userVipResolver.resolve(activityVoList, ActivityVo::getUserId,((obj, vipOrNot)->{
            obj.setVipOrNot(vipOrNot);
        }));

        page.setRecords(activityVoList);

        return page;
    }

    private void convertActivitySignUpUserList(List<ActivityVo> activityVoList, List<ActivitySignup> activitySignupList) {
        activityVoList.forEach(item->{
            List<ActivitySignup> activitySignupListOne = activitySignupList.stream().filter(DO->DO.getActivityId().equals(item.getId())).limit(4).collect(Collectors.toList());
            List<ActivityUserSignUpVo> userSignUpVoList = activitySignupListOne.stream().map(DO->{
                ActivityUserSignUpVo signUpVo = new ActivityUserSignUpVo();
                signUpVo.setUserId(DO.getUserId());
                return signUpVo;
            }).collect(Collectors.toList());
            userInfoResolver.resolve(userSignUpVoList,ActivityUserSignUpVo::getUserId,(obj,nickname,headPic)->{
                obj.setNickname(nickname);
                obj.setHeadPic(headPic);
            });
            userVipResolver.resolve(userSignUpVoList, ActivityUserSignUpVo::getUserId,((obj, vipOrNot)->{
                obj.setVipOrNot(vipOrNot);
            }));
            item.setUserSignUpVoList(userSignUpVoList);
        });
    }

    public void cancelActivity(ActivityCancelParam activityCancelParam, LoginUser loginUser) {
        Activity activity = activityService.getById(activityCancelParam.getActivityId());
        if (activity == null) {
            throw new ServiceException("活动不存在");
        }
        if (activity.getUserId().compareTo(loginUser.getUserId()) != 0) {
            throw new ServiceException("活动必须本人取消");
        }
        if (ActivityStatusEnum.end.getValue() == activity.getStatus()) {
            throw new ServiceException("已结束的活动不可取消");
        }
        if (ActivityStatusEnum.cancel.getValue() == activity.getStatus()) {
            throw new ServiceException("活动已取消，无需重复操作");
        }
        // 检查并更新活动状态
        updateActivityStatusAuto(activity);
        // 查询已报名的数据
        List<ActivitySignup> activitySignupList = activitySignupService.list(new QueryWrapper<ActivitySignup>()
                .eq("activity_id", activity.getId()).eq("status",ActivitySignUpStatusEnum.sign_up_ed.getValue())
        );
        // 发起退款
        activitySignupList.forEach(activitySignup->{
                // 当前如果已经不是报名成功的状态 不考虑
                if(ActivitySignUpStatusEnum.sign_up_ed.getValue() != activitySignup.getStatus()) {
                    return;
                }
                singleActivityRefund(activitySignup, activity);
                // 通知 报名的用户
                User user = userService.getById(activitySignup.getUserId());
                applicationEventPublisher.publishEvent(WxMpMessageEvent.builder()
                        .miniAppPath("pages/detail/detail?activityId=" + activitySignup.getActivityId())
                        .userId(user.getId())
                        .pushTemplateEnum(PushTemplateEnumNew.ACTIVITY_CANCEL_SUCCESS)
                        .templateDataList(PushTemplateEnumNew.ACTIVITY_CANCEL_SUCCESS(
                                activity.getTitle(),
                                "组局人："+activity.getContactName(),
                                activity.getContactPhone(),
                                WzDateUtil.date2String(new Date(),WzDateUtil.TIME_FORMAT_A))
                        )
                        .build()
                );
        });
        activityService.update(new UpdateWrapper<Activity>()
                .set("status",ActivityStatusEnum.cancel.getValue())
                .set("cancel_date",new Date())
                .eq("id",activity.getId()));

    }

    /***
     * 独立出一个事务 单条处理 这个事务失败 回滚当前用户的报名信息
     * @param activitySignup
     * @return
     */
    public void singleActivityRefund(ActivitySignup activitySignup,Activity activity) {
        refundAndCancelSignUpActivity(activitySignup, activity);
    }

    public ActivitySignUpVo userSignUpActivity(ActivitySignUpParam activitySignUpParam, LoginUser loginUser) {
        Activity activity = activityService.getById(activitySignUpParam.getActivityId());
        if (activity == null) {
            throw new ServiceException("活动不存在");
        }
        if (StringUtils.isEmpty(activitySignUpParam.getUserPhone())) {
            throw new ServiceException("手机号必填");
        }
        if (StringUtils.isEmpty(activitySignUpParam.getIdCardNumber())) {
            throw new ServiceException("身份证号必填");
        }
        if (activity.getSignUpEndDate() != null && new Date().compareTo(activity.getSignUpEndDate()) > 0) {
            throw new ServiceException("报名已截止");
        }
        if (ActivityStatusEnum.signUpCutOff.getValue() == activity.getStatus()) {
            throw new ServiceException("报名已截止");
        }
        if (ActivityStatusEnum.end.getValue() == activity.getStatus()) {
            throw new ServiceException("报名已结束");
        }
        if (ActivityStatusEnum.cancel.getValue() == activity.getStatus()) {
            throw new ServiceException("活动已取消，不可报名");
        }
        if(!StringUtils.isEmpty(activitySignUpParam.getUserPhone())) {
            if(!PhoneUtil.isPhone(activitySignUpParam.getUserPhone())) {
                throw new ServiceException("手机号不正确");
            }
        }
        if(!StringUtils.isEmpty(activitySignUpParam.getIdCardNumber())) {
            if(!IDUtils.isIDNumber(activitySignUpParam.getIdCardNumber())) {
                throw new ServiceException("身份证号不正确");
            }
        }


        // todo 这里可能出现 并发支付 报名人数超过规定人数 这个目前能接受 后面优化
        if (activity.getSignUpCount() >= activity.getMaxSignUpCount()) {
            throw new ServiceException("报名人数已满");
        }
        // 检查用户是否 信息完整
        User currentUser = appUserService.userNeedInfoComplete(loginUser);
        // 补充性别和手机号
        if (StringUtils.isEmpty(activitySignUpParam.getUserPhone())) {
            activitySignUpParam.setUserPhone(currentUser.getPhone());
        }
        if (activitySignUpParam.getGender() == null) {
            activitySignUpParam.setGender(currentUser.getGender());
        }
        // 活动形式
        ActivityFormTypeEnum formTypeEnum = ActivityFormTypeEnum.getEnumByValue(activity.getFormType());
        if (ActivityFormTypeEnum.only_man.equals(formTypeEnum) && currentUser.getGender() == UserGenderEnum.woman.getValue()) {
            throw new ServiceException("该活动仅限男生报名");
        }
        if (ActivityFormTypeEnum.only_woman.equals(formTypeEnum) && currentUser.getGender() == UserGenderEnum.man.getValue()) {
            throw new ServiceException("该活动仅限女生报名");
        }
        // 查询已报名的数据
        List<ActivitySignup> activitySignupList = activitySignupService.list(new QueryWrapper<ActivitySignup>()
                .eq("activity_id",activitySignUpParam.getActivityId()).eq("status",ActivitySignUpStatusEnum.sign_up_ed.getValue())
        );
        // 指定男女人数的需要判断
        if (ActivityFormTypeEnum.diy.equals(formTypeEnum)) {
            if (!CollectionUtils.isEmpty(activitySignupList)) {
                Long manCount = activitySignupList.stream().filter(item->UserGenderEnum.man.getValue() == item.getGender()).count();
                if (manCount >= activity.getMaxManCount()) {
                    throw new ServiceException("该活动男生报名已满");
                }
                Long woManCount = activitySignupList.stream().filter(item->UserGenderEnum.woman.getValue() == item.getGender()).count();
                if (woManCount >= activity.getMaxWomanCount()) {
                    throw new ServiceException("该活动女生报名已满");
                }
           }
        }
        // 读取当前用户是否已存在报名信息
        List<ActivitySignup> activitySignupListOne =  activitySignupList.stream().filter(item->item.getUserId().equals(loginUser.getUserId())).collect(Collectors.toList());
        // 定义一个 报名对象
        ActivitySignup activitySignup = null;
        if (!CollectionUtils.isEmpty(activitySignupListOne)) {
            activitySignup = activitySignupListOne.get(0);
            if (ActivitySignUpStatusEnum.sign_up_ed.getValue() == activitySignup.getStatus()) {
                throw new ServiceException("你已成功报名无需重复报名");
            }
//            if (ActivitySignUpStatusEnum.cancel_sign_up.getValue() == activitySignup.getStatus()) {
//                throw new ServiceException("你已取消报名不可以再次报名");
//            }
        }
        // 用户从未报名过 此处生成新的报名
        else {
            // 生成报名信息
            activitySignup = initActivitySignup(activity,currentUser,activitySignUpParam);
            // 先插入生成id
            activitySignupService.save(activitySignup);
        }
        // 判断是否需要生成支付单
        if (ActivitySignUpStatusEnum.sign_up_ed.getValue() == activitySignup.getStatus()) {
            ActivitySignUpVo signUpVo = new ActivitySignUpVo();
            signUpVo.setActivityId(activity.getId());
            signUpVo.setNeedPay(false);
            // 报名成功
            // 更新活动报名数量
            activityService.update(
                    new UpdateWrapper<Activity>()
                            .setSql("sign_up_count = sign_up_count + 1")
                            .eq("id", activitySignup.getActivityId())
            );
            applicationEventPublisher.publishEvent(
                    ActivitySignUpSuccessEvent.builder()
                            .activity(activity)
                            .signup(activitySignup)
                            .build());
            return signUpVo;
        }
        // 需要支付的报名订单
        if (ActivitySignUpStatusEnum.sign_up_wait_pay.getValue() == activitySignup.getStatus()) {
            // 支付单每次都需要重新生成
            WxPay wxPay = initOrderPay(activitySignup);
            wxPayService.save(wxPay);
            ActivitySignUpVo signUpVo = new ActivitySignUpVo();
            signUpVo.setActivityId(activity.getId());
            signUpVo.setNeedPay(true);
            // 创建微信小程序单
            WxPayJSAPIDto wxPayJSAPIDto = new WxPayJSAPIDto();
            wxPayJSAPIDto.setOpenId(currentUser.getMiniOpenid());
            wxPayJSAPIDto.setSourceTypeEnum(WxUserAuthSourceTypeEnum.MINI_PROGRAM_OPENID);
            wxPayJSAPIDto.setOrderNum(wxPay.getOrderNumber());
            wxPayJSAPIDto.setOrderDesc(StringUtils.removeNonBmpUnicodes(activity.getTitle()));
            wxPayJSAPIDto.setOrderMoney(wxPay.getActualMoney());
            PayResultDTO payResultDTO = wxPayManger.createWxJsapiTradeInfo(wxPayJSAPIDto);
            signUpVo.setPayResultDTO(payResultDTO);
            return signUpVo;
        }
        throw new ServiceException("服务异常");
    }


    private ActivitySignup initActivitySignup(Activity activity, User currentUser, ActivitySignUpParam signUpParam) {
        ActivitySignup activitySignup = new ActivitySignup();
        activitySignup.setActivityId(activity.getId());
        activitySignup.setChargeType(activity.getChargeType());
        activitySignup.setPayWay(activity.getPayWay());

        activitySignup.setCreateUserId(currentUser.getId());
        activitySignup.setUserId(currentUser.getId());
        activitySignup.setNickname(signUpParam.getNickname());
        activitySignup.setGender(signUpParam.getGender());
        activitySignup.setPhone(signUpParam.getUserPhone());
        activitySignup.setRealName(signUpParam.getRealName());
        activitySignup.setIdCardNumber(signUpParam.getIdCardNumber());
        activitySignup.setOutUser(false);
        BigDecimal actualPay = activity.getPrice().subtract(activity.getDiscountedPrice());
        // 免费或者线下支付 都无需创建 支付单 写入报名表即可
        if (ActivityChargeTypeEnum.free.getValue() == activity.getChargeType() || ActivityPayWayEnum.off_line.getValue() == activity.getPayWay() || actualPay.compareTo(BigDecimal.ZERO) == 0
        ) {
            activitySignup.setPayDate(new Date());
            activitySignup.setActualMoney(BigDecimal.ZERO);
            activitySignup.setDiscountPrice(BigDecimal.ZERO);
            activitySignup.setStatus(ActivitySignUpStatusEnum.sign_up_ed.getValue());
        }
        // 需要支付的情况
        else {
            if (ActivityDiscountTypeEnum.woman_discount.getValue() == activity.getDiscountType() && currentUser.getGender() == UserGenderEnum.woman.getValue()) {
                // 用户优惠金额
                activitySignup.setDiscountPrice(activity.getDiscountedPrice());
            }else {
                activitySignup.setDiscountPrice(BigDecimal.ZERO);
            }
            // 实际支付金额
            activitySignup.setActualMoney(actualPay);
            activitySignup.setStatus(ActivitySignUpStatusEnum.sign_up_wait_pay.getValue());
        }
        return activitySignup;
    }
    private WxPay initOrderPay(ActivitySignup activitySignup) {
        WxPay wxPay = new WxPay();
        wxPay.setCreateDate(new Date());
        wxPay.setStatus(PayStatusEnum.WAITING_PAY.getValue());
        wxPay.setUserId(activitySignup.getCreateUserId());
        wxPay.setActualMoney(activitySignup.getActualMoney());
        wxPay.setTotalMoney(activitySignup.getActualMoney());
        wxPay.setOrderNumber(OrderNumberUtil.getOrderNumberBySourceType(OrderSourceTypeEnum.activity_sign_up));
        wxPay.setSourceId(activitySignup.getId());
        wxPay.setSourceType(OrderSourceTypeEnum.activity_sign_up.getValue());
        return wxPay;
    }

    public void userCancelSignUpActivity(ActivitySignUpParam activitySignUpParam, LoginUser loginUser) {
        // 活动
        Activity activity = activityService.getById(activitySignUpParam.getActivityId());
        // 报名信息
        ActivitySignup activitySignup = activitySignupService.getOne(
                new QueryWrapper<ActivitySignup>().eq("activity_id", activitySignUpParam.getActivityId())
                        .eq("user_id", loginUser.getUserId())
                        .orderByDesc("create_date").last("limit 1")
        );
        if(activitySignup == null) {
            throw new ServiceException("当前报名信息不存在");
        }
        // 报名信息
        if(ActivitySignUpStatusEnum.cancel_sign_up.getValue() == activitySignup.getStatus()) {
            throw new ServiceException("当前报名已取消");
        }
        // 用户自己发起 需要检验是否在无责发起的范围
        if (activity.getStatus() > ActivityStatusEnum.signUpCutOff.getValue()) {
            throw new ServiceException("当前活动状态不允许取消");
        }
        // 用户自己发起 需要检验是否在无责发起的范围
        if (ActivityCancelBeforeTypeEnum.cannot.getValue() == activity.getCancelFreeType()) {
            throw new ServiceException("当前活动不允许取消");
        }
        // 用户自己发起 需要检验是否在无责发起的范围
        if (System.currentTimeMillis() > activity.getCancelFreeDate().getTime()) {
            throw new ServiceException("当前时间已超过取消时间，不可取消");
        }
        // 查看如果当前报名信息已经结算成功 不能自动退款
        UserAccountInout accountInout = userAccountInoutService.getOne(
                new QueryWrapper<UserAccountInout>().eq("source_id", activitySignup.getId())
                        .eq("source_type", AccountSourceTypeEnum.activity_sign_up_fee.getValue()), false
        );
        if(accountInout != null && AccountInoutStatusEnum.Received.getValue() == accountInout.getStatus()) {
            throw new ServiceException("当前费用已结算至活动组织者，不可操作");
        }

        refundAndCancelSignUpActivity(activitySignup,activity);
        // 发送微信通知给创建者
        User user = userService.getById(activity.getUserId());
//        applicationEventPublisher.publishEvent(WxMpMessageEvent.builder()
//                .miniAppPath("pages/detail/detail?activityId=" + activitySignup.getActivityId())
//                .userId(user.getId())
//                .pushTemplateEnum(PushTemplateEnum.ACTIVITY_SIGN_UP_CANCEL)
//                .templateDataList(PushTemplateEnum.getACTIVITY_SIGN_UP_CANCEL_Data(activitySignup.getNickname()+" "+ activitySignup.getPhone(), activity.getTitle(), activitySignup.getCreateDate()))
//                .build()
//        );

        applicationEventPublisher.publishEvent(WxMpMessageEvent.builder()
                .miniAppPath("pages/detail/detail?activityId=" + activitySignup.getActivityId())
                .userId(user.getId())
                .pushTemplateEnum(PushTemplateEnumNew.ACTIVITY_CANCEL_SUCCESS)
                .templateDataList(PushTemplateEnumNew.ACTIVITY_CANCEL_SUCCESS(
                        activity.getTitle(),
                        "报名人："+activitySignup.getNickname(),
                        activitySignup.getPhone(),
                        WzDateUtil.date2String(new Date(),WzDateUtil.TIME_FORMAT_A)))
                .build()
        );

        applicationEventPublisher.publishEvent(UserMessageEvent.builder()
                .userId(user.getId())
                .type(MessageTypeEnum.ACTIVITY_MESSAGE)
                .withContent("活动报名取消", activity.getTitle())
                .withActivityParam(activitySignup.getActivityId())
                .build());

    }

    private void refundAndCancelSignUpActivity(ActivitySignup activitySignup, Activity activity){

        //开始执行取消 逻辑
        activitySignupService.update(
                new UpdateWrapper<ActivitySignup>()
                        .set("status",ActivitySignUpStatusEnum.cancel_sign_up.getValue())
                        .set("cancel_date", new Date())
                        .eq("id",activitySignup.getId())
        );
        activityService.update(
                new UpdateWrapper<Activity>()
                        .setSql("sign_up_count = sign_up_count - 1")
                        .eq("id", activitySignup.getActivityId())
        );
        if(activitySignup.getSettleDate() != null) {
            log.info("已提前结算的金额不允许退款，{}", activitySignup);
            return;
        }
        // 判断是否发起退款
        if (ActivityChargeTypeEnum.AA_before.getValue() == activitySignup.getChargeType() && activitySignup.getActualMoney() != null && StringUtils.isNotEmpty(activitySignup.getOrderNumber())) {
            // 读取对应的支付单
            WxPay wxPay = wxPayService.getOne(new QueryWrapper<WxPay>().eq("order_number",activitySignup.getOrderNumber()),false);
            if(wxPay != null) {
                wxPay.setStatus(PayStatusEnum.REFUND.getValue());
                wxPayService.updateById(wxPay);
                // 更新 账户明细
                if(!userAccountInoutService.update(
                        new UpdateWrapper<UserAccountInout>().set("status", AccountInoutStatusEnum.un_Received.getValue())
                                .eq("source_type",AccountSourceTypeEnum.activity_sign_up_fee.getValue())
                                .eq("source_id", activitySignup.getId()))){
                    throw new ServiceException("操作异常，请重新操作");
                }
                // 冻结金额扣减
                userAccountService.update(
                        new UpdateWrapper<UserAccount>()
                        .setSql("freeze_amount = freeze_amount -" + activitySignup.getActualMoney())
                        .eq("user_id", activity.getUserId())
                );
                // 事件通知 日志
                applicationEventPublisher.publishEvent(CancelActivitySignUpSuccessEvent.builder()
                        .activity(activity)
                        .signup(activitySignup)
                        .build()
                );
                log.info("refundAndCancelSignUpActivity:activitySignup:{},activity:{}", activitySignup, activity);
            }
        }
    }

    public Page<ActivityVo> getUserSignupActivityPage(Page page, String searchKey, LoginUser loginUser) {
        // 这里如果要做 关键字搜索 要么连表 要么不做分页  选择不做分页
        List<ActivitySignup> activitySignupList;
        Wrapper<ActivitySignup> activityWrapper = new QueryWrapper<ActivitySignup>()
                // 固有规则 已结束 已取消 不展示
                .eq("user_id", loginUser.getUserId())
                .in("status", Arrays.asList(ActivitySignUpStatusEnum.sign_up_ed.getValue(),ActivitySignUpStatusEnum.cancel_sign_up.getValue()))
                .orderByDesc("create_date");
        if (StringUtils.isEmpty(searchKey)) {
            Page<ActivitySignup> signupPage = activitySignupService.page(page,activityWrapper);
            activitySignupList = signupPage.getRecords();
        }else {
            // 不做分页 所有读取出来
            activitySignupList = activitySignupService.list(activityWrapper);
        }

        List<ActivityCategory> categoryList = activityCategoryService.list(null);
        final List<Activity> activityList;
        // 首屏置顶优先
        if (!CollectionUtils.isEmpty(activitySignupList)) {
            List<Long> activityIdList = activitySignupList.stream().map(ActivitySignup::getActivityId).collect(Collectors.toList());
            Double lngLatArray[] = tokenService.getLngLatArray();
            log.info("经纬度：{}",lngLatArray);
            activityList = activityService.list(
                    new QueryWrapper<Activity>()
                            .and(StringUtils.isNotEmpty(searchKey),
                                    w->w.like("title", searchKey)
                                            .or().like("location_name", searchKey))
                            .in("id", activityIdList)
                            .select(lngLatArray == null ? "*" :
                    String.format("*,ST_Distance_Sphere(ST_GeomFromText('POINT(%f %f)',4326), location) AS distance", lngLatArray[0], lngLatArray[1])));
        }else {
            activityList = new ArrayList<>();
        }
        // 加工返回前端VO
        List<ActivityVo> activityVoList = new ArrayList<>();
        // 分页数据
        activitySignupList.forEach(item->{
            List<Activity> activityListOne = activityList.stream().filter(DO->DO.getId().equals(item.getActivityId())).collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(activityListOne)) {
                ActivityVo activityVo = convertActivityHomeVo(activityListOne.get(0), categoryList);
                activityVo.setSignUpStatus(item.getStatus());
                // 是否已经结算
                if(item.getSettleDate() != null) {
                    activityVo.setSettleDate(WzDateUtil.date2String(item.getSettleDate(),WzDateUtil.TIME_FORMAT_A));
                }
                activityVoList.add(activityVo);
            }
        });
        // 更新
        userInfoResolver.resolve(activityVoList,ActivityVo::getUserId,(obj, nickname,headPic)->{
            obj.setUserName(nickname);
            obj.setUserHeadPic(headPic + "?x-oss-process=image/resize,h_100,m_lfit");
        });
        page.setRecords(activityVoList);

        return page;
    }

    public Page<ActivityVo> getUserCreateActivityPage(Page page, String searchKey, LoginUser loginUser) {
        List<ActivityCategory> categoryList = activityCategoryService.list(null);
        Double lngLatArray[] = tokenService.getLngLatArray();
        log.info("经纬度：{}",lngLatArray);
        Page<Activity> activityPage =  activityService.page(page,
                new QueryWrapper<Activity>()
                        .and(StringUtils.isNotEmpty(searchKey),
                                w->w.like("title", searchKey)
                                        .or().like("location_name", searchKey))
                        .eq("user_id", loginUser.getUserId())
                        .orderByDesc("create_date")
                        .select(lngLatArray == null ? "*" :
                                String.format("*,ST_Distance_Sphere(ST_GeomFromText('POINT(%f %f)',4326), location) AS distance", lngLatArray[0], lngLatArray[1])));
        // 加工返回前端VO
        List<ActivityVo> activityVoList = new ArrayList<>();
        // 分页数据
        activityPage.getRecords().forEach(item->{
            ActivityVo activityVo = convertActivityHomeVo(item, categoryList);
            activityVoList.add(activityVo);
        });

        // 更新
        userInfoResolver.resolve(activityVoList,ActivityVo::getUserId,(obj, nickname,headPic)->{
            obj.setUserName(nickname);
            obj.setUserHeadPic(headPic + "?x-oss-process=image/resize,h_100,m_lfit");
        });
        page.setRecords(activityVoList);

        return page;
    }

    public Page<ActivityVo> getUserAssociationActivityPage(Page page, Long userId) {
        Wrapper<ActivitySignup> activityWrapper = new QueryWrapper<ActivitySignup>()
                // 固有规则 已结束 已取消 不展示
                .eq("user_id", userId)
                .eq("status", ActivitySignUpStatusEnum.sign_up_ed.getValue())
                .orderByDesc("create_date").select("activity_id as activityId");
        // 报名的活动
        List<ActivitySignup> signupList = activitySignupService.list(activityWrapper);
        final List<Long> userSignUpActivityIdList;
        if (!CollectionUtils.isEmpty(signupList)) {
            userSignUpActivityIdList = signupList.stream().map(ActivitySignup::getActivityId).collect(Collectors.toList());
        }else {
            userSignUpActivityIdList = null;
        }
        Double lngLatArray[] = tokenService.getLngLatArray();
        Page<Activity> activityPage = activityService.page(page,
                new QueryWrapper<Activity>().and(w->w.eq("user_id", userId)
                        .or(userSignUpActivityIdList != null,  m->m.in("id",userSignUpActivityIdList)))
                        .eq("show_public", true)
                        .ne("status", ActivityStatusEnum.cancel.getValue())
                        .select(lngLatArray == null ? "*" :
                                String.format("*,ST_Distance_Sphere(ST_GeomFromText('POINT(%f %f)',4326), location) AS distance", lngLatArray[0], lngLatArray[1]))
                        .orderByDesc("end_date")
        );
        // 分类
        List<ActivityCategory> categoryList = activityCategoryService.list(null);
        final List<ActivitySignup> activitySignupList;
        // 首屏置顶优先
        if (!CollectionUtils.isEmpty(activityPage.getRecords())) {
            List<Long> activityIdList = activityPage.getRecords().stream().map(Activity::getId).collect(Collectors.toList());
            activitySignupList = activitySignupService.list(
                    new QueryWrapper<ActivitySignup>()
                            .in("activity_id",activityIdList)
                            .eq("status", ActivitySignUpStatusEnum.sign_up_ed.getValue())
                            .orderByAsc(Arrays.asList("activity_id","pay_date"))
            );
        }else {
            activitySignupList = new ArrayList<>();
        }
        // 加工返回前端VO
        List<ActivityVo> activityVoList = new ArrayList<>();
        // 分页数据
        activityPage.getRecords().forEach(item->{
            ActivityVo activityVo = convertActivityHomeVo(item , categoryList);
            // 处理报名时间
            activityVo.setDateDayShow(WzDateUtil.date2String(item.getStartDate(),WzDateUtil.DATE_FORMAT_D));
            activityVoList.add(activityVo);
        });
        // 报名人信息
        convertActivitySignUpUserList(activityVoList,activitySignupList);
        // 更新
        userInfoResolver.resolve(activityVoList,ActivityVo::getUserId,(obj, nickname,headPic)->{
            obj.setUserName(nickname);
            obj.setUserHeadPic(headPic + "?x-oss-process=image/resize,h_100,m_lfit");
        });
        page.setRecords(activityVoList);

        return page;
    }

    /***
     * 活动报名费用结算到账户
     * @param activityId
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void activitySignUpSettle2Account(Long activityId) {
        log.info("activitySignUpSettle2Account 开始 => activityId:{}",activityId);
        List<ActivitySignup> signupList = activitySignupService.list(
                new QueryWrapper<ActivitySignup>()
                        .eq("activity_id", activityId)
                        .eq("status", ActivitySignUpStatusEnum.sign_up_ed.getValue())
                        .eq("pay_way", ActivityPayWayEnum.pay_online.getValue())
                        // 没有结算过的 才需要
                        .isNull("settle_date")
                        .isNotNull("order_number")
        );
        if(CollectionUtils.isEmpty(signupList)) {
            return;
        }
        // 报名活动id集合
        List<Long> signupIdList = signupList.stream().map(ActivitySignup::getId).collect(Collectors.toList());
        // 待入账的数据账单
        List<UserAccountInout> inoutList = userAccountInoutService.list(
                new QueryWrapper<UserAccountInout>()
                        .in("source_id", signupIdList)
                        .eq("source_type", OrderSourceTypeEnum.activity_sign_up.getValue())
                        .eq("status", AccountInoutStatusEnum.auditing.getValue())
        );
        inoutList.forEach(item->{
            // 更新账户余额
            userAccountService.update(new UpdateWrapper<UserAccount>()
                    .setSql("amount = amount + " + item.getAmount())
                    .setSql("freeze_amount = freeze_amount - " + item.getAmount())
                    .eq("user_id", item.getUserId())
            );
            // 更新出入账明细
            userAccountInoutService.update(new UpdateWrapper<UserAccountInout>()
                    .set("status",AccountInoutStatusEnum.Received.getValue())
                    .eq("id", item.getId())
            );
        });
        // 统一更新 结算时间
        activitySignupService.update(new UpdateWrapper<ActivitySignup>().set("settle_date",new Date()).in("id",signupIdList));
        log.info("activitySignUpSettle2Account 结束 => activityId:{}",activityId);
    }

    public void commitUserActivitySignUpFee(ActivitySignUpParam activitySignUpParam, LoginUser loginUser) {
        // 活动
        Activity activity = activityService.getById(activitySignUpParam.getActivityId());
        // 报名信息
        ActivitySignup activitySignup = activitySignupService.getOne(
                new QueryWrapper<ActivitySignup>().eq("activity_id", activitySignUpParam.getActivityId())
                        .eq("user_id", loginUser.getUserId())
                        .eq("status", ActivitySignUpStatusEnum.sign_up_ed.getValue())
                        .orderByDesc("create_date").last("limit 1")
        );
        if(activitySignup == null || activity == null) {
            throw new ServiceException("当前报名信息不存在");
        }
        if(ActivityPayWayEnum.off_line.getValue() == activitySignup.getPayWay() || ActivityChargeTypeEnum.free.getValue() == activitySignup.getChargeType()) {
            throw new ServiceException("当前活动无需在线支付费用");
        }
        UserAccountInout accountInout = userAccountInoutService.getOne(
                new QueryWrapper<UserAccountInout>().eq("source_id", activitySignup.getId())
                        .eq("source_type", AccountSourceTypeEnum.activity_sign_up_fee.getValue()), false
        );
        if(accountInout == null) {
            throw new ServiceException("未找到结算信息");
        }
        if(AccountInoutStatusEnum.auditing.getValue() != accountInout.getStatus()) {
            throw new ServiceException("当前费用已处理，无需重复结算");
        }
        activitySignup.setSettleDate(new Date());
        activitySignupService.updateById(activitySignup);

        // 更新账户余额
        userAccountService.update(new UpdateWrapper<UserAccount>()
                .setSql("amount = amount + " + accountInout.getAmount())
                .setSql("freeze_amount = freeze_amount - " + accountInout.getAmount())
                .eq("user_id", accountInout.getUserId())
        );
        // 更新出入账明细
        userAccountInoutService.update(new UpdateWrapper<UserAccountInout>()
                .set("status",AccountInoutStatusEnum.Received.getValue())
                .eq("id", accountInout.getId())
        );

    }

    /***
     * 获取商家下活动分页列表 在商家主页
     * @param page
     * @param merchantId
     * @return
     */
    public Page<ActivityVo> getMerchantActivityPage(Page page, Long merchantId) {
        List<ActivityCategory> categoryList = activityCategoryService.list(null);
        Double lngLatArray[] = tokenService.getLngLatArray();
        log.info("经纬度：{}",lngLatArray);
        Page<Activity> activityPage =  activityService.page(page,
                new QueryWrapper<Activity>()
                        .eq("merchant_id", merchantId)
                        .eq("show_public", true)
                        // 已结束 进行中 报名中 都可以展示
                        .le("status", ActivityStatusEnum.end.getValue())
                        .orderByAsc( "status")
                        .orderByDesc("id")
                        .select(lngLatArray == null ? "*" :
                                String.format("*,ST_Distance_Sphere(ST_GeomFromText('POINT(%f %f)',4326), location) AS distance", lngLatArray[0], lngLatArray[1])));
        // 加工返回前端VO
        List<ActivityVo> activityVoList = new ArrayList<>();
        // 分页数据
        activityPage.getRecords().forEach(item->{
            ActivityVo activityVo = convertActivityHomeVo(item, categoryList);
            activityVoList.add(activityVo);
        });

        // 更新
        userInfoResolver.resolve(activityVoList,ActivityVo::getUserId,(obj, nickname,headPic)->{
            obj.setUserName(nickname);
            obj.setUserHeadPic(headPic + "?x-oss-process=image/resize,h_100,m_lfit");
        });
        page.setRecords(activityVoList);

        return page;
    }

    public List<ActivityVo> getUserActivityIngList(Long userId) {
        Wrapper<ActivitySignup> activityWrapper = new QueryWrapper<ActivitySignup>()
                // 固有规则 已结束 已取消 不展示
                .eq("user_id", userId)
                .eq("status", ActivitySignUpStatusEnum.sign_up_ed.getValue())
                .orderByDesc("create_date").select("activity_id as activityId");
        // 报名的活动
        List<ActivitySignup> signupList = activitySignupService.list(activityWrapper);
        final List<Long> userSignUpActivityIdList;
        if (!CollectionUtils.isEmpty(signupList)) {
            userSignUpActivityIdList = signupList.stream().map(ActivitySignup::getActivityId).collect(Collectors.toList());
        }else {
            userSignUpActivityIdList = null;
        }
        Double lngLatArray[] = tokenService.getLngLatArray();
        List<Activity> activityList = activityService.list(
                new QueryWrapper<Activity>().and(w->w.eq("user_id", userId)
                                .or(userSignUpActivityIdList != null,  m->m.in("id",userSignUpActivityIdList)))
                        .eq("show_public", true)
                        .isNotNull("product_id")
                        .le("status", ActivityStatusEnum.inProgress.getValue())
                        .select(lngLatArray == null ? "*" :
                                String.format("*,ST_Distance_Sphere(ST_GeomFromText('POINT(%f %f)',4326), location) AS distance", lngLatArray[0], lngLatArray[1]))
                        .orderByDesc("end_date")
        );
        // 分类
        List<ActivityCategory> categoryList = activityCategoryService.list(null);
        final List<ActivitySignup> activitySignupList;
        // 首屏置顶优先
        if (!CollectionUtils.isEmpty(activityList)) {
            List<Long> activityIdList = activityList.stream().map(Activity::getId).collect(Collectors.toList());
            activitySignupList = activitySignupService.list(
                    new QueryWrapper<ActivitySignup>()
                            .in("activity_id",activityIdList)
                            .eq("status", ActivitySignUpStatusEnum.sign_up_ed.getValue())
                            .orderByAsc(Arrays.asList("activity_id","pay_date"))
            );
        }else {
            activitySignupList = new ArrayList<>();
        }
        // 加工返回前端VO
        List<ActivityVo> activityVoList = new ArrayList<>();
        // 分页数据
        activityList.forEach(item->{
            ActivityVo activityVo = convertActivityHomeVo(item , categoryList);
            // 处理报名时间
            activityVo.setDateDayShow(WzDateUtil.date2String(item.getStartDate(),WzDateUtil.DATE_FORMAT_D));
            // 读取套餐
            if (item.getProductId() != null) {
                MerchantProductVO merchantProductVO = appProductService.getProductById(item.getProductId());
                activityVo.setMerchantProductVO(merchantProductVO);
            }
            activityVoList.add(activityVo);
        });
        // 报名人信息
        convertActivitySignUpUserList(activityVoList,activitySignupList);
        // 更新
        userInfoResolver.resolve(activityVoList,ActivityVo::getUserId,(obj, nickname,headPic)->{
            obj.setUserName(nickname);
            obj.setUserHeadPic(headPic + "?x-oss-process=image/resize,h_100,m_lfit");
        });

        return activityVoList;
    }
}
